#include "HotAreaSubscribable.hpp"

HotAreaSubscribable::HotAreaSubscribable()
{
	zeroMembers();
}

HotAreaSubscribable::~HotAreaSubscribable()
{
	clearThis();
}

void HotAreaSubscribable::clearThis()
{
	mCreator = nullptr;

	mSubscribers.clear();

	zeroMembers();
}

void HotAreaSubscribable::zeroMembers()
{
	// do nothing.
}

void HotAreaSubscribable::clear()
{
	clearThis();

	TrafficActorHotArea::clear();
}

void HotAreaSubscribable::setCreator(SocketBasePtr pCreator)
{
	mCreator = pCreator;
}

SocketBasePtr HotAreaSubscribable::getCreator() const
{
	return mCreator;
}

void HotAreaSubscribable::addSubscriber(SocketBasePtr pSocket)
{
	if (pSocket == nullptr)
	{
		return;
	}

	mSubscribers.insert(pSocket);
}

void HotAreaSubscribable::removeSubscriber(SocketBasePtr pSocket)
{
	if (pSocket == nullptr)
	{
		return;
	}

	auto it = mSubscribers.find(pSocket);
	if (it == mSubscribers.end())
	{
		return;
	}

	mSubscribers.erase(it);
}

void HotAreaSubscribable::dispatch(const Message& msg)
{
	for (auto it = mSubscribers.begin(); it != mSubscribers.end(); ++it)
	{
		Message msgClone = msg;
		(*it)->send(std::move(msgClone));
	}
}

void HotAreaSubscribable::sendEverything(SocketBasePtr pSocket)
{
	{
		// first create actors
		HotArea::FromAnyAddDeleteTrafficActors change;

		change.set_hotareaid(mId);
		for (auto it = mActorIdSet.begin(); it != mActorIdSet.end(); it++)
		{
			const TrafficActor& actor = mpActors[*it];
			if (actor.getRuntimeId() < 0)
			{
				continue;
			}
			change.add_addedactorids(actor.getRuntimeId());
			change.add_addedtypes(actor.getActorType());
			change.add_addedassetids(actor.getAssetId());
			const vec3& position = actor.getWorldPosition();
			const vec3& rotation = actor.getWorldRotation();
			const vec3& size = actor.getObjectSpaceSize();
			change.add_addedpositionrotationsizes(position.x);
			change.add_addedpositionrotationsizes(position.y);
			change.add_addedpositionrotationsizes(position.z);
			change.add_addedpositionrotationsizes(rotation.x);
			change.add_addedpositionrotationsizes(rotation.y);
			change.add_addedpositionrotationsizes(rotation.z);
			change.add_addedpositionrotationsizes(size.x);
			change.add_addedpositionrotationsizes(size.y);
			change.add_addedpositionrotationsizes(size.z);
		}

		pSocket->send(HotArea::EFromAnyAddDeleteTrafficActors, change);
	}

	{
		// flags
		HotArea::FromAnyUpdateTrafficActorFlags change;

		change.set_hotareaid(mId);
		for (auto it = mActorIdSet.begin(); it != mActorIdSet.end(); it++)
		{
			const TrafficActor& actor = mpActors[*it];
			if (actor.getRuntimeId() < 0)
			{
				continue;
			}
			std::uint32_t flag = actor.getFlags();
			if (flag == 0)
			{
				continue;
			}

			change.add_actorids(actor.getRuntimeId());
			change.add_flags(flag);
		}

		pSocket->send(HotArea::EFromAnyUpdateTrafficActorFlags, change);
	}

	{
		// custom properties
		HotArea::FromAnyUpdateTrafficActorCustomProperties change;

		change.set_hotareaid(mId);

		std::string* pCustomPropertyDatas = change.mutable_custompropertydatas();

		for (auto it = mActorIdSet.begin(); it != mActorIdSet.end(); it++)
		{
			const TrafficActor& actor = mpActors[*it];
			if (actor.getRuntimeId() < 0)
			{
				continue;
			}
			const std::vector<unsigned char>& properties = actor.getCustomProperties();
			if (properties.size() == 0)
			{
				continue;
			}

			change.add_actorids(actor.getRuntimeId());
			change.add_custompropertysizes((std::uint32_t)(properties.size()));

			size_t oldSize = pCustomPropertyDatas->size();
			pCustomPropertyDatas->resize(oldSize + properties.size());
			memcpy(
				&(pCustomPropertyDatas->operator[](oldSize)), 
				properties.data(), 
				properties.size());
		}

		pSocket->send(HotArea::EFromAnyUpdateTrafficActorCustomProperties, change);
	}
}
